home *** CD-ROM | disk | FTP | other *** search
/ More MacCube 1: Arcade Games / More MacCube Vol 1 Arcade Games.bin / Games⁄Arcade / Bolo / More information / Sample Code / Std Autopilot / BF_Events.c < prev    next >
Encoding:
Text File  |  1995-05-13  |  14.8 KB  |  457 lines  |  [TEXT/KAHL]

  1. // Bolo code (C) Stuart Cheshire <cheshire@cs.stanford.edu> 1987-1995.
  2. // All rights reserved. This code is owned by Stuart Cheshire and is donated
  3. // free of charge for non-commercial use. You may not use this code in any
  4. // product sold for commercial profit, except shareware priced at $25 or less.
  5.  
  6. #include <Power.h>
  7. #include <EPPC.h>
  8. #include <Desk.h>
  9. #include <Scrap.h>
  10. #include <QuickDraw.h>
  11.  
  12. #include "BrainFrame.h"
  13. #include "BF_Main.h"
  14. #include "BF_Globals.h"
  15. #include "BF_ResourceIDs.h"
  16. #include "BF_Events.h"
  17. #include "BF_Utils.h"
  18. #include "BF_IAC.h"
  19. #include "BF_Prefs.h"
  20. #include "BF_Interface.h"
  21.  
  22. export MenuHandle AppleMenu = NULL;
  23. export MenuHandle FileMenu  = NULL;
  24. export MenuHandle EditMenu  = NULL;
  25. export MenuHandle BFMenu    = NULL;
  26.  
  27. export Boolean WNE_Busy;        // set if not idle (ie stuff happening on screen)
  28. export Boolean WNE_Intensive;    // means application temporarily wants Maximum CPU
  29.  
  30. local Boolean newFrontWindow = TRUE;
  31. local Boolean MyFrontWindow  = TRUE;
  32.  
  33. // If File menu completely disabled, we have a movable modal dialog at the front
  34. #define MovableModalDialogActive ((*FileMenu)->enableFlags == 0)
  35.  
  36. local ConnectionInfo *findconnection(WindowPtr win)
  37.     {
  38.     ConnectionInfo *conn = Connections;
  39.     while(conn) if (conn->win == win) break; else conn = conn->next;
  40.     if (!conn) conn = Connections;
  41.     return(conn);
  42.     }
  43.  
  44. local void setmenus(void)
  45.     {
  46.     ConnectionInfo *conn = findconnection(FrontWindow());
  47.     // if have a movable modal dialog at the front don't change menu settings
  48.     if (MovableModalDialogActive) return;
  49.     
  50.     /***** Set items in the File menu *****/
  51.     
  52.     /***** Set items in the Edit menu *****/
  53.     
  54.     /***** Set items in the BrainFrame menu *****/
  55.     CheckItem(BFMenu, bm_60, prefs.frametime == 1);
  56.     CheckItem(BFMenu, bm_30, prefs.frametime == 2);
  57.     CheckItem(BFMenu, bm_20, prefs.frametime == 3);
  58.     CheckItem(BFMenu, bm_15, prefs.frametime == 4);
  59.     }
  60.  
  61. /*************************************************************************/
  62.  
  63. export OSErr openwindow(void)
  64.     {
  65.     OSErr retcode;
  66.     ConnectionInfo *conn = (ConnectionInfo *)NewPtr(sizeof(ConnectionInfo));
  67.     if (!conn) return(1);
  68.     
  69.     retcode = PPCToolBoxConnect(conn);
  70.     if (retcode) { DisposPtr((Ptr)conn); return(retcode); }
  71.     
  72.     retcode = BFInterfaceOpen(conn);
  73.     if (retcode) { PPCToolBoxDisconnect(conn); DisposPtr((Ptr)conn); return(retcode); }
  74.     conn->next = Connections;
  75.     Connections = conn;
  76.     CallBolo(conn, BoloResume);
  77.     newFrontWindow = TRUE;
  78.     return(noErr);
  79.     }
  80.  
  81. local void closewindow(WindowPtr win)
  82.     {
  83.     ConnectionInfo **conn = &Connections;
  84.     while(*conn) if ((*conn)->win == win) break; else conn = &(*conn)->next;
  85.     if (*conn)
  86.         {
  87.         ConnectionInfo *c = *conn;
  88.         PPCToolBoxDisconnect(c);
  89.         BFInterfaceClose(c);
  90.         *conn = c->next;
  91.         DisposePtr((Ptr)c);
  92.         newFrontWindow = TRUE;
  93.         }
  94.     }
  95.  
  96. local Boolean docommand(u_long com)
  97.     {
  98.     Boolean returncode = TRUE;
  99.     short item = com & 0xFFFF, mark;
  100.     MenuHandle mh = GetMHandle(com >> 16);
  101.     Str255 menutext;
  102.     WindowPtr fwin = FrontWindow();
  103.     GetItem(mh, item, menutext);
  104.     GetItemMark(mh, item, &mark);
  105.     switch(com >> 16)
  106.         {
  107.         case 0       :    break;
  108.         case appleID:
  109.             if (item > 1) OpenDeskAcc(menutext);
  110.             else
  111.                 {
  112.                 short dummy;
  113.                 DialogPtr modal = OpenMovableModalDialog(MM_about);
  114.                 SetCursor(&qd.arrow);
  115.                 set_OutlineOK(modal, 2);
  116.                 DisableItem(AppleMenu, 1);
  117.                 MovableModalDialog(NULL, &dummy);
  118.                 EnableItem(AppleMenu, 1);
  119.                 CloseMovableModalDialog(modal);
  120.                 }
  121.             break;
  122.         case fileID:
  123.             switch(item)
  124.                 {
  125.                 case fm_open:        openwindow();                            break;
  126.                 case fm_close:      closewindow(fwin);                        break;
  127.                 case fm_quit:       quitting = TRUE; returncode = FALSE;    break;
  128.                 }
  129.             break;
  130.         case editID:
  131.             // if desk accessory is frontmost, undo/cut/copy/paste/clear go to that
  132.             if (item <= em_clear && ((WindowPeek)fwin)->windowKind != dialogKind)
  133.                 SystemEdit(item-1);
  134.             else switch(item)
  135.                 {
  136.                 case em_undo:        break;
  137.                 case em_cut:        DlgCut(fwin);        break;
  138.                 case em_copy:        DlgCopy(fwin);        break;
  139.                 case em_paste:        DlgPaste(fwin);        break;
  140.                 case em_clear:        DlgDelete(fwin);    break;
  141.                 }
  142.             break;
  143.         case BF_ID:
  144.             switch(item)
  145.                 {
  146.                 case bm_60: prefs.frametime = 1; break;
  147.                 case bm_30: prefs.frametime = 2; break;
  148.                 case bm_20: prefs.frametime = 3; break;
  149.                 case bm_15: prefs.frametime = 4; break;
  150.                 }
  151.             
  152.         default: BFInterfaceMenu(findconnection(fwin), com >> 16, item); break;
  153.         }
  154.     save_prefs();    // If prefs have changed, write them to disk
  155.     HiliteMenu(0);    // zero means unhilite all hilited menus
  156.     return(returncode);
  157.     }
  158.  
  159. local GDHandle findDominantDevice(Rect *theRect)
  160.     {
  161.     long sectArea, greatestArea = 0;
  162.     GDHandle dominantGDevice = NULL, dev = GetDeviceList();
  163.     while (dev)                                                // for every device
  164.         {
  165.         if (TestDeviceAttribute(dev, screenDevice) &&        // that's an active screen
  166.             TestDeviceAttribute(dev, screenActive))
  167.             {
  168.             Rect r;
  169.             SectRect(theRect, &(**dev).gdRect, &r);        // find out the intersection area
  170.             sectArea = (long)(r.right - r.left) * (long)(r.bottom - r.top);
  171.             if (greatestArea < sectArea) { greatestArea = sectArea; dominantGDevice = dev; }
  172.             }
  173.         dev = GetNextDevice(dev);
  174.         }
  175.     return(dominantGDevice);
  176.     }
  177.  
  178. #define topLeft(r)        (((Point *) &(r))[0])
  179. #define botRight(r)        (((Point *) &(r))[1])
  180.  
  181. // The window will be zoomed to fill the screen it is already on,
  182. // subject to the size constraints of the Limits rectangle.
  183. // win           = window to be zoomed
  184. // partCode      = inZoomIn or inZoomOut
  185. // front         = Bring window to front after zooming? (Normally TRUE)
  186. // Limits.top    = minimum allowable window height
  187. // Limits.left   = minimum allowable window width
  188. // Limits.bottom = maximum sensible window height + 1
  189. // Limits.right  = maximum sensible window width  + 1
  190. // Note: The maximums are actually one greater than the actual maximum allowed sizes,
  191. // for consistency with GrowWindow
  192. local void SmartZoomWindow(WindowPtr win, short partCode, Boolean front, const Rect *Limits)
  193.     {
  194.     // Zooming in is easy. Only zooming out needs extra smarts
  195.     if (partCode == inZoomOut)
  196.         {
  197.         short hsize = Limits->right  - 1;
  198.         short vsize = Limits->bottom - 1;
  199.         WindowPeek wp = (WindowPeek)win;
  200.         Rect    *windRect       = &(*wp->strucRgn)->rgnBBox;
  201.         Rect    *zoomRect       = &(*(WStateDataHandle)wp->dataHandle)->stdState;
  202.         Rect     globalPortRect = win->portRect;
  203.         Rect     target         = qd.screenBits.bounds;    // Start with a reasonable default
  204.         target.top += GetMBarHeight();
  205.         LocalToGlobal(&topLeft(globalPortRect));        // calculate the window's portRect
  206.         LocalToGlobal(&botRight(globalPortRect));        // in global coordinates
  207.         
  208.         // *** TASK 1
  209.         // Pick a monitor (if necessary) and work out the maximum allowable rectangle on it
  210.         if (sysenvirons.hasColorQD)
  211.             {
  212.             GDHandle dev = findDominantDevice(windRect);
  213.             if (dev)
  214.                 {
  215.                 target = (*dev)->gdRect;
  216.                 if (dev == GetMainDevice()) target.top += GetMBarHeight();
  217.                 }
  218.             }
  219.  
  220.         // *** TASK 2
  221.         // Reduce the logical target rectangle a little to allow for the frame
  222.         // around the window, and a couple of pixels extra for aesthetic reasons
  223.         target.top    += 2 + (globalPortRect.top  - windRect->top        );
  224.         target.left   += 2 + (globalPortRect.left - windRect->left       );
  225.         target.bottom -= 1 + (windRect->bottom    - globalPortRect.bottom);
  226.         target.right  -= 1 + (windRect->right     - globalPortRect.right );
  227.  
  228.         // *** TASK 3
  229.         // Make sure the target rectangle is big enough for the minimum size
  230.         if (target.bottom < target.top  + Limits->top ) target.bottom = target.top  + Limits->top;
  231.         if (target.right  < target.left + Limits->left) target.right  = target.left + Limits->left;
  232.  
  233.         // *** TASK 4
  234.         // Make sure the desired (maximum) size fits within the target rectangle
  235.         if (vsize > target.bottom - target.top) vsize = target.bottom - target.top;
  236.         if (hsize > target.right - target.left) hsize = target.right - target.left;
  237.         
  238.         // *** TASK 5
  239.         // Start off with a zoom rectangle obtained by simply resizing the window
  240.         // in the current position
  241.         zoomRect->top    = globalPortRect.top;
  242.         zoomRect->left   = globalPortRect.left;
  243.         zoomRect->bottom = globalPortRect.top  + vsize;
  244.         zoomRect->right  = globalPortRect.left + hsize;
  245.  
  246.         // *** TASK 6
  247.         // If Window is falls outside the limits, shift it the minimum amount to bring it inside
  248.         if (zoomRect->top    < target.top   ) OffsetRect(zoomRect, 0, target.top - zoomRect->top);
  249.         if (zoomRect->left   < target.left  ) OffsetRect(zoomRect, target.left - zoomRect->left, 0);
  250.         if (zoomRect->bottom > target.bottom) OffsetRect(zoomRect, 0, target.bottom - zoomRect->bottom);
  251.         if (zoomRect->right  > target.right ) OffsetRect(zoomRect, target.right - zoomRect->right, 0);
  252.         }
  253.     ZoomWindow(win, partCode, front);
  254.     }
  255.  
  256. local Boolean checkmousedown(EventRecord *evrec)
  257.     {
  258.     static const Rect SizeLimits = { 80, 300, 0x7FFF, 0x7FFF };
  259.     WindowPtr win;
  260.     short partcode = FindWindow(evrec->where,&win);
  261.     switch(partcode)
  262.         {
  263.         case inDesk       : break;
  264.         case inMenuBar      : setmenus();
  265.                             return(docommand(MenuSelect(evrec->where)));    break;
  266.         case inSysWindow  : SystemClick(evrec, win);                        break;
  267.         case inContent      : 
  268.             // In modal state, ignore clicks in windows
  269.             if (MovableModalDialogActive) { SysBeep(30); break; }
  270.             if (win != FrontWindow()) SelectWindow(win); //else clickedinwindow(evrec);
  271.             break;
  272.         case inDrag          :
  273.             // In modal state can only drag front window
  274.             if (MovableModalDialogActive && win != FrontWindow()) SysBeep(30);
  275.             else DragWindow(win, evrec->where, &qd.screenBits.bounds);
  276.             break;
  277.         case inGrow       :
  278.             {
  279.             long newsize = GrowWindow(win, evrec->where, &SizeLimits);
  280.             short *sp = (short*)&newsize;
  281.             if (newsize) { SizeWindow(win, sp[1], sp[0], TRUE); BFInterfaceUpdateWindow(findconnection(win)); }
  282.             }
  283.             break;
  284.         case inGoAway      : closewindow(win);                break;
  285.         case inZoomIn     :
  286.         case inZoomOut    :
  287.             if (TrackBox(win, evrec->where, partcode))
  288.                 {
  289.                 SetPort(win);
  290.                 EraseRect(&win->portRect);
  291.                 SmartZoomWindow(win, partcode, TRUE, &SizeLimits);
  292.                 BFInterfaceUpdateWindow(findconnection(win));
  293.                 }
  294.             break;
  295.         }
  296.     return(TRUE);        // No quit -- continue running
  297.     }
  298.  
  299. local void activatewindow(WindowPtr win, Boolean activate)
  300.     {
  301.     ConnectionInfo *conn = findconnection(win);
  302.     if (conn) CallBolo(conn, activate ? BoloResume : BoloSuspend);
  303.     newFrontWindow = TRUE;
  304.     }
  305.  
  306. /*************************************************************************/
  307.  
  308. // this ONLY gets called when one of my windows NEEDS to be updated.
  309. // ie. ((WindowPeek)win)->updateRgn) is non-empty.
  310. // foreground is called so that the map area is filled in immediately.
  311. // Note: Even if not drawing anything, must do BeginUpdate/EndUpdate to
  312. // poke the OS to let it know we have handled the updatewindow event.
  313. local void handle_update_event(WindowPtr win)
  314.     {
  315.     ConnectionInfo *conn = findconnection(win);
  316.     GrafPtr savePort;
  317.     GetPort(&savePort);
  318.     SetPort(win);
  319.     BeginUpdate(win);
  320.     if (conn) BFInterfaceUpdateWindow(conn);
  321.     EndUpdate(win);
  322.     SetPort(savePort);
  323.     }
  324.  
  325. local void updatemenus(void)
  326.     {
  327.     Boolean bool = findconnection(FrontWindow()) != NULL;
  328.     if (MyFrontWindow != bool)
  329.         {
  330.         MyFrontWindow = bool;
  331.         if (MyFrontWindow) EnableItem(BFMenu, 0);
  332.         else
  333.             {
  334.             int i;
  335.             for (i = bm_60; i<=bm_end; i++) CheckItem(BFMenu, i, FALSE);
  336.             DisableItem(BFMenu, 0);
  337.             }
  338.         DrawMenuBar();
  339.         }
  340.     }
  341.  
  342. local void handle_null_event(void)
  343.     {
  344.     ConnectionInfo *conn = Connections;
  345.     if (newFrontWindow) { updatemenus(); newFrontWindow = FALSE; }
  346.     while (conn) { BFInterfaceIdle(conn); conn = conn->next; }
  347.     }
  348.  
  349. // handle_dialog_event handles mouse, key, redraw etc. events for Dialog Manager windows
  350. // It returns true if an item is hit in a frontmost (movable) modal dialog
  351.  
  352. local Boolean handle_dialog_event(EventRecord *e, ModalFilterProcPtr FilterProc, short *item)
  353.     {
  354.     DialogPtr dp = FrontWindow();
  355.     Boolean event = FALSE;
  356.     *item = 0;
  357.     
  358.     // Install appropriate event filter if a modeless dialog is the front window
  359.     //if (dp == window[DLG_MESSAGE]) FilterProc = message_dialog_filter;
  360.     // ... etc. for other modeless dialogs, some day
  361.  
  362.     // See if FilterProc handles event
  363.     if (FilterProc) event = FilterProc(dp, e, item);
  364.     
  365.     // Pass command keys through to docommand()
  366.     if (!event && e->what == keyDown && e->modifiers & cmdKey)
  367.         { setmenus(); docommand(MenuKey(e->message & charCodeMask)); return(FALSE); }
  368.     
  369.     // If not a special keyboard equivalent, see what DialogSelect makes of it
  370.     // (DialogSelect handles update events, activate, deactivate etc.)
  371.     if (!event) event = DialogSelect(e, &dp, item);
  372.     
  373.     // If some dialog button event has happened, see if it belongs to a modeless dialog
  374.     if (event)
  375.         {
  376.         //if (dp == window[DLG_MESSAGE]) { message_dialog_event(*item); return(FALSE); }
  377.         // ... etc. for other modeless dialogs, some day
  378.         }
  379.     return(event);
  380.     }
  381.  
  382. // Note:
  383. // Returns TRUE after an AppleEvent to indicate an item 'hit' so that control is
  384. // handed back to modal dialogs in case the AppleEvent has caused some change
  385. local Boolean handle_normal_event(EventRecord *e)
  386.     {
  387.     switch (e->what)
  388.         {
  389.         case mouseDown    : checkmousedown(e); break;
  390.         case keyDown      : if (e->modifiers & cmdKey)
  391.                                 {
  392.                                 setmenus();
  393.                                 docommand(MenuKey(e->message & charCodeMask));
  394.                                 }
  395.                             break;
  396.  
  397.         case updateEvt    : handle_update_event((WindowPtr)e->message); break;
  398.  
  399.         case activateEvt  : activatewindow((WindowPtr)e->message, e->modifiers & activeFlag); break;
  400.  
  401.         case nullEvent :
  402.         case mouseUp : case keyUp      : case autoKey   :
  403.         case diskEvt : case networkEvt : case driverEvt :
  404.         case app1Evt : case app2Evt    : case app3Evt   : break;    // these never happen
  405.         case osEvt   : if (e->message >> 24 == suspendResumeMessage)
  406.                             {
  407.                             frontapp = e->message & resumeFlag;
  408.                             if (frontapp)
  409.                                 {
  410.                                 SetCursor(&qd.arrow);
  411.                                 TEFromScrap();
  412.                                 activatewindow(FrontWindow(), 1);
  413.                                 }
  414.                             else
  415.                                 {
  416.                                 ZeroScrap();
  417.                                 TEToScrap();
  418.                                 activatewindow(FrontWindow(), 0);
  419.                                 }
  420.                             }
  421.                             break;
  422.         case kHighLevelEvent: AEProcessAppleEvent(e); return(TRUE);
  423.         }
  424.     return(FALSE);
  425.     }
  426.  
  427. // If handle_next_event is being used to handle events for a movable modal dialog, then
  428. // the FilterProc will be non-null and MacMainLoop will return TRUE if an item is hit
  429.  
  430. export Boolean handle_next_event(ModalFilterProcPtr FilterProc, short *item)
  431.     {
  432.     static u_long busytime, last_null;
  433.     u_long this_time = TickCount();
  434.     u_long sleep;
  435.     EventRecord e;
  436.     short dummy;
  437.     if (!item) item = &dummy;
  438.     *item = 0;
  439.  
  440.     if (WNE_Busy) { WNE_Busy = FALSE; busytime = this_time; }
  441.     if (WNE_Intensive) { WNE_Intensive = FALSE; sleep = 0; }
  442.     else
  443.         {
  444.         sleep = (this_time - busytime) >> 6;
  445.         if (sleep < prefs.frametime) sleep = prefs.frametime;
  446.         else if (frontapp && sleep > 6) sleep = 6;    // max is 1/10 sec in foreground
  447.         else if (sleep > 12) sleep = 12;            // or 1/5 sec in background
  448.         if (sleep < this_time - last_null) sleep = 0; else sleep -= this_time - last_null;
  449.         }
  450.     WaitNextEvent(everyEvent, &e, sleep, NULL);
  451.     if (e.what == nullEvent && this_time != last_null)
  452.         { last_null = this_time; handle_null_event(); }
  453.  
  454.     if (IsDialogEvent(&e)) return(handle_dialog_event(&e, FilterProc, item));
  455.     else return(handle_normal_event(&e));
  456.     }
  457.